package net.ericaro.neojavagen;

import java.security.InvalidParameterException;
import java.util.regex.Pattern;

import net.ericaro.neojavagen.blocks.StatementExpression;
import net.ericaro.neojavagen.packages.JavadocLiteral;
import net.ericaro.neojavagen.types.BooleanLiteral;
import net.ericaro.neojavagen.types.CharacterLiteral;
import net.ericaro.neojavagen.types.FloatingPointLiteral;
import net.ericaro.neojavagen.types.Identifier;
import net.ericaro.neojavagen.types.IntegerLiteral;
import net.ericaro.neojavagen.types.NullLiteral;
import net.ericaro.neojavagen.types.StringLiteral;

/**
 * Java literals factory:
 * IntegerLiteral
 * FloatingPointLiteral
 * CharacterLiteral
 * StringLiteral
 * BooleanLiteral
 * NullLiteral
 * 
 * @author eric
 */
public class Literals {

	private static class UnsecureBooleanLiteral implements BooleanLiteral {
		private String value;

		public UnsecureBooleanLiteral(String value) {
			this.value = value;
		}

		@Override
		public String toString() {
			return value;
		}
	}

	private static class UnsecureCharacterLiteral implements CharacterLiteral {
		private String value;

		public UnsecureCharacterLiteral(String value) {
			this.value = value;
		}

		@Override
		public String toString() {
			return value;
		}
	}

	private static class UnsecureFloatingPointLiteral implements FloatingPointLiteral {
		private String value;

		public UnsecureFloatingPointLiteral(String value) {
			this.value = value;
		}

		@Override
		public String toString() {
			return value;
		}
	}

	private static class UnsecureIdentifierLiteral implements Identifier {
		private String value;

		public UnsecureIdentifierLiteral(String value) {
			this.value = value;
		}

		@Override
		public String toString() {
			return value;
		}
	}

	private static class UnsecureIntegerLiteral implements IntegerLiteral {
		private String value;

		public UnsecureIntegerLiteral(String value) {
			this.value = value;
		}

		@Override
		public String toString() {
			return value;
		}
	}

	private static class UnsecureJavadocLiteral implements JavadocLiteral {
		private String value;

		public UnsecureJavadocLiteral(String value) {
			this.value = value;
		}

		@Override
		public String toString() {
			return value;
		}
	}

	private static class UnsecureNullLiteral implements NullLiteral {
		private String value;

		public UnsecureNullLiteral(String value) {
			this.value = value;
		}

		@Override
		public String toString() {
			return value;
		}
	}

	private static class UnsecureStringLiteral implements StringLiteral {
		private String value;

		public UnsecureStringLiteral(String value) {
			this.value = value;
		}

		@Override
		public String toString() {
			return value;
		}
	}

	public static BooleanLiteral booleanLiteral(boolean value) {
		return new UnsecureBooleanLiteral(value ? "true" : "false");
	}

	public static CharacterLiteral characterLiteral(char v) {
		String src = escape(v);

		return new UnsecureCharacterLiteral("'" + src + "'");
	}

	private static String escape(char v) {
		String src = String.valueOf(v); // will be the src representation of src
		if (v == '\b')
			src = "\\b";
		else if (v == '\t')
			src = "\\t";
		else if (v == '\n')
			src = "\\n";
		else if (v == '\f')
			src = "\\f";
		else if (v == '\r')
			src = "\\r";
		else if (v == '\"')
			src = "\\\"";
		else if (v == '\'')
			src = "\\'";
		else if (v == '\\')
			src = "\\\\";
		return src;
	}

	public static FloatingPointLiteral floatingPointLiteral(double v) {
		return floatingPointLiteral(String.valueOf(v));
	}

	public static FloatingPointLiteral floatingPointLiteral(float v) {
		return floatingPointLiteral(String.valueOf(v));
	}

	public static FloatingPointLiteral floatingPointLiteral(String v) {
		Double.parseDouble(v);// check and return
		return new UnsecureFloatingPointLiteral(v);
	}

	public static Identifier identifier(String name) {
		if (!Pattern.matches("(\\w|_)(\\w|\\d|_)*", name))
			throw new InvalidParameterException(name + " does not match identifier : ");
		return new UnsecureIdentifierLiteral(name);
	}

	public static IntegerLiteral intLiteral(int i) {
		return intLiteral(String.valueOf(i));
	}

	public static IntegerLiteral intLiteral(String i) {
		Integer.parseInt(i);// check and return
		return new UnsecureIntegerLiteral(i);
	}

	public static JavadocLiteral javadocLiteral(String content) {
		return new UnsecureJavadocLiteral(content.replace("*/", "*&#47;"));
	}

	public static NullLiteral nullLiteral() {
		return new UnsecureNullLiteral("null");
	}

	/**
	 * not secured against code injection....
	 * 
	 * @param singleStatement
	 * @return
	 */
	public static StatementExpression statementExpression(final String singleStatement) {
		return new StatementExpression() {
			@Override
			public String toString() {
				return singleStatement;
			}
		};
	}

	public static StringLiteral stringLiteral(String v) {
		char[] chars = v.toCharArray();
		StringBuilder sb = new StringBuilder();
		sb.append('"');
		for (int i = 0; i < chars.length; i++)
			sb.append(escape(chars[i]));
		sb.append('"');
		return new UnsecureStringLiteral(sb.toString());
	}

}
